package tests;

import static org.junit.Assert.*;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

import org.junit.Before;
import org.junit.Test;

import engine.ARFFReader;
import engine.Cocomo;
import engine.Logger;
import engine.Project;
import engine.Ranges;
import engine.Similarity;
import engine.Project.ProjectProperty;

public class ProjectTest {
	Project p;
	String pcName;
	String pcValue;

	@Before
	public void stub(){
		p = new Project();

	}
	public void init(){
		pcName = "ACAP";
		pcValue = "Very_Low";
		ProjectProperty pp = new ProjectProperty(pcName, pcValue);
		p.addCharacteristic(pp);
	}

	public void initInt(){
		pcName = "LOC";
		pcValue = "2000";
		ProjectProperty pp = new ProjectProperty(pcName, pcValue);
		p.addCharacteristic(pp);
	}

	@Test
	public void testCorrectPropertyName() {
		init();
		assertEquals(true, p.getCharacteristic(pcName).getName().equals(pcName));
	}

	@Test
	public void testCorrectPropertyValue() {
		init();
		assertEquals(true, p.getCharacteristic(pcName).getValue() == 1.46);
	}

	@Test
	public void testCorrectPropertyValueInt() {
		initInt();
		assertEquals(pcValue, (int)(p.getCharacteristic(pcName).getValue())+"");
	}

	@Test
	public void testBidirectionalCompare() {
		Project p1 = new Project();
		p1.addCharacteristic(new ProjectProperty("RELY", "Nominal"));
		p1.addCharacteristic(new ProjectProperty("VEXP", "Low"));
		p1.addCharacteristic(new ProjectProperty("TOOL", "Very_High"));


		Project p2 = new Project();
		p2.addCharacteristic(new ProjectProperty("RELY", "High"));
		p2.addCharacteristic(new ProjectProperty("VEXP", "Low"));


		HashMap<String, Double> range = new HashMap<String, Double>();

		range.put("RELY", Math.abs(p1.getCharacteristic("RELY").getValue()-p2.getCharacteristic("RELY").getValue()));
		range.put("VEXP", Math.abs(p1.getCharacteristic("VEXP").getValue()-p2.getCharacteristic("VEXP").getValue()));
		range.put("TOOL", 0.0);

		assertEquals(p1.compareTo(p2, range), p2.compareTo(p1, range), 0.000000001);

		//		p.addCharacteristic(key)

	}

	@Test
	public void testPerfectCompare() {
		Project p1 = new Project();
		p1.addCharacteristic(new ProjectProperty("RELY", "Nominal"));
		p1.addCharacteristic(new ProjectProperty("VEXP", "Low"));
		p1.addCharacteristic(new ProjectProperty("TOOL", "Very_High"));


		Project p2 = new Project();
		p2.addCharacteristic(new ProjectProperty("RELY", "Nominal"));
		p2.addCharacteristic(new ProjectProperty("VEXP", "Low"));


		HashMap<String, Double> range = new HashMap<String, Double>();

		range.put("RELY", Math.abs(p1.getCharacteristic("RELY").getValue()-p2.getCharacteristic("RELY").getValue()));
		range.put("VEXP", Math.abs(p1.getCharacteristic("VEXP").getValue()-p2.getCharacteristic("VEXP").getValue()));
		range.put("TOOL", 0.0);

		assertEquals(1.0, p1.compareTo(p2, range), 0.000000001);

		//		p.addCharacteristic(key)

	}

	@Test
	public void testBaaaaadCompare() {
		Project p1 = new Project();
		p1.addCharacteristic(new ProjectProperty("RELY", "Nominal"));

		Project p2 = new Project();
		p2.addCharacteristic(new ProjectProperty("VEXP", "Low"));

		HashMap<String, Double> range = new HashMap<String, Double>();

		range.put("RELY", 0.0);
		range.put("VEXP", 0.0);

		assertEquals(0.0, p1.compareTo(p2, range), 0.000000001);
	}

	@Test
	public void testQ01() throws IOException{
		ArrayList<Project> p = null;
		try {
			p = ARFFReader.parse("cocomonasa.arff");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		int overEighty = 0;
		
		double avgOff = 0;
		int numNear = 0, numOff = 0;
		
		for(int i = 0; i < p.size(); i++){
			ArrayList<Project> temp = (ArrayList<Project>)p.clone();
			
			int num = 0;
			for (Project pr : p) {
				if (pr.getCharacteristic("ACT_EFFORT") != null)
					num++;
			}
			
			Project removed = temp.remove(i);
			
			
			ProjectProperty removedProp = removed.deleteCharacteristic("ACT_EFFORT");
			double removedValue = removedProp.getValue();
			removed.tag = new Object();
			
			
			
			HashMap<String,Double> ranges = Ranges.calculateUsing(ARFFReader.getProjectDescriptors("cocomonasa.arff"), temp, removed);
			
			double[] sim = Similarity.compareSimilarity(temp, removed, ranges );//range);
			
//			System.out.println("temp.size() = " + temp.size() +", sim.length = " + sim.length+", p.size() = " + p.size());
			
			final String[] types = new String[]{
					"Organic",
					"Semi-Detached",
					"Embedded"
			};
			
			int typeIndex = 0;
			
			
			// BEGIN trying to calculate the best type for the "removed" project
			double error = Double.MAX_VALUE;
			
			double kloc = removed.getCharacteristic("LOC").getValue();
			double eaf = removed.getEAF();
			
			for (int j=0; j<types.length; j++) {
				double newError = Math.abs(removedValue - Cocomo.effort(types[j], kloc, eaf));
				
				if (newError < error) {
					typeIndex = j;
					error = newError;
				}
			}
			//END trying to calculate the best type for the "removed" project
			
			
//			double[] errs = new double[3];
//			
//			for (int type=0; type<types.length; type++) {
//				errs[type] = Math.abs(Cocomo.effort(types[type], removed.getCharacteristic("LOC").getValue(), removed.getEAF()) - removedValue);
//			}
//			System.out.println("\nErrors from "+removedValue+": " + Arrays.toString(errs)+"\n");
			
			double effort = 0;//Cocomo.effort("Embedded", removed.getCharacteristic("LOC").getValue(), removed.getEAF());
			double totalSimilarity =0;
			double simThres = 0.0;
			for(int j = 0; j < sim.length; j++){
//				System.out.println(sim[j]);
				if(sim[j] >= simThres){
					totalSimilarity += sim[j];
				}
			}
			
			
//			for(int j = 0; j < sim.length; j++){
//				if(sim[j] >= simThres){
//					effort += Cocomo.effort("Embedded", removed.getCharacteristic("LOC").getValue(), removed.getEAF()) * (Similarity.compare(pr, newProject, ranges))
//					/ totalSimilarity;
//					effort += (temp.get(i).getCharacteristic("ACT_EFFORT").getValue() * removed.getCharacteristic("LOC").getValue() / temp.get(i).getCharacteristic("LOC").getValue()) * sim[j]/totalSimilarity;
//				}
//			}
			for (Project pr : temp) {
				
				double simt = Similarity.compare(pr, removed, ranges);
				
				if (simt >= simThres) {
					effort += Cocomo.effort(types[typeIndex], removed.getCharacteristic("LOC").getValue(), removed.getEAF()) * simt
					/ totalSimilarity;

//					effort += (pr.getCharacteristic("ACT_EFFORT").getValue() * removed.getCharacteristic("LOC").getValue() / pr.getCharacteristic("LOC").getValue()) * (simt)/totalSimilarity;
				} 
			}
			
			removed.tag = null;
			removed.addCharacteristic(removedProp);
			
//			Logger.log("estimated " + effort +" when real was " + removedValue);
			
			double off = Math.abs(effort-removedValue) / removedValue;
			
			avgOff += off / p.size();
			
			if(off <= 0.3){
				overEighty++;
				numNear++;
			} else {
//				System.out.println("Not counting " + effort +". To far from " + removedValue);
				numOff++;
			}
			
		}
		System.out.println("Avg off = " + avgOff);
		System.out.println("numNear,numOff = " + numNear+","+numOff);
		
		
		double percent = ((double)overEighty/p.size());
		System.out.println(percent+"");
		if(percent > 0.8){
//			assert(true);
			assertTrue(true);
//			System.out.println("GEH");
		}else{
			assertTrue(false);
		}
		
	}





}
